package com.itmei.mqregister.config;

import com.itmei.mqregister.enums.mq.ExchangeConfigEnum;
import com.itmei.mqregister.enums.mq.QueueConfigEnum;
import com.itmei.mqregister.enums.mq.RabbitMqQueueEnum;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author itmei
 */
@Configuration
public class RabbitMqConfig {

    ///**
    // * 声明队列
    // * @return
    // */
    //@Bean
    //public Queue directQueue(){
    //    //持久 - 如果我们声明一个持久队列，则为真（该队列将在服务器重启后继续存在）
    //    return new Queue(RabbitMqQueueEnum.DEFAULT_DIRECT.getQueueName(),false);
    //}
    //
    ///**
    // * 声明交换机
    // * @return
    // */
    //@Bean
    //public DirectExchange directExchange(){
    //    //交换器名称、是否持久化、是否自动删除
    //    return new DirectExchange(RabbitMqQueueEnum.DEFAULT_DIRECT.getExchangeName(),true,false);
    //}
    //
    ///***
    // * 队列绑定到交换机上
    // * 并且设置路由关键字
    // */
    //@Bean
    //public Binding binding(Queue queue,DirectExchange exchange){
    //    return BindingBuilder.bind(queue).to(exchange).with(RabbitMqQueueEnum.DEFAULT_DIRECT.getRoutingKey());
    //}


    /**
     * 用于动态创建队列和交换机
     * @param rabbitTemplate rabbitMq的模板对象
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(RabbitTemplate rabbitTemplate){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate);
        //默认就是true
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    /**
     * 绑定
     * @param rabbitAdmin RabbitAdmin 实例，用于管理队列和交换机的声明
     * @return
     */
    @Bean("createQueue")
    public Object createQueue(RabbitAdmin rabbitAdmin) {
        // 遍历队列枚举
        RabbitMqQueueEnum.toList().forEach(rabbitMqQueueEnum -> {
            //创建交换机
            createExchangeHandle(rabbitAdmin,rabbitMqQueueEnum);
            // 创建对列
            createQueueHandle(rabbitAdmin,rabbitMqQueueEnum);
            // 绑定交换机和对列
            createBindingHandle(rabbitAdmin,rabbitMqQueueEnum);
        });
        return null;
    }


    /**
     * 注册交换机的方法，根据传入的队列枚举配置创建相应类型的交换机。
     * @param rabbitAdmin RabbitAdmin 实例，用于管理队列和交换机的声明
     * @param rabbitMqQueueEnum 自定义队列枚举，包含交换机的配置信息，包含交换机的配置信息
     */
    private void createExchangeHandle(RabbitAdmin rabbitAdmin, RabbitMqQueueEnum rabbitMqQueueEnum) {
        // 获取当前队列的交换机配置
        ExchangeConfigEnum exchangeConfigEnum = rabbitMqQueueEnum.getExchangeConfigEnum();
        String exchangeName = rabbitMqQueueEnum.getExchangeName();

        // 检查是否为延迟交换机
        if (rabbitMqQueueEnum.isDelayedExchange()) {
            // 创建并声明延迟交换机
            rabbitAdmin.declareExchange(new CustomDelayedExchange(
                    // 交换机名称
                    exchangeName,
                    // 交换机是否持久化
                    exchangeConfigEnum.isDurable(),
                    // 交换机是否自动删除
                    exchangeConfigEnum.isAutoDelete(),
                    // 交换机类型
                    exchangeConfigEnum.getType().name().toLowerCase()
            ));
        } else {
            // 创建并声明普通交换机
            createStandardExchange(rabbitAdmin, exchangeName, exchangeConfigEnum);
        }
    }

    /**
     * 创建并声明标准交换机的方法。
     * @param rabbitAdmin RabbitAdmin 实例，用于声明交换机
     * @param exchangeName 交换机的名称
     * @param exchangeConfigEnum 交换机的配置枚举，包含持久化和自动删除等信息
     */
    private void createStandardExchange(RabbitAdmin rabbitAdmin, String exchangeName, ExchangeConfigEnum exchangeConfigEnum) {
        AbstractExchange exchange;

        // 根据交换机类型创建对应的交换机实例
        switch (exchangeConfigEnum.getType()) {
            case FANOUT:
                // 创建 Fanout 交换机
                exchange = new FanoutExchange(exchangeName, exchangeConfigEnum.isDurable(), exchangeConfigEnum.isAutoDelete());
                break;
            case TOPIC:
                // 创建 Topic 交换机
                exchange = new TopicExchange(exchangeName, exchangeConfigEnum.isDurable(), exchangeConfigEnum.isAutoDelete());
                break;
            case DIRECT:
                // 创建 Direct 交换机
                exchange = new DirectExchange(exchangeName, exchangeConfigEnum.isDurable(), exchangeConfigEnum.isAutoDelete());
                break;
            default:
                // 不支持的交换机类型，直接返回
                return;
        }

        // 声明创建的交换机
        rabbitAdmin.declareExchange(exchange);
    }

    /**
     * 注册队列
     * @param rabbitAdmin RabbitAdmin 实例，用于管理队列和交换机的声明
     * @param rabbitMqQueueEnum 自定义队列枚举，包含交换机的配置信息
     */
    public void createQueueHandle(RabbitAdmin rabbitAdmin, RabbitMqQueueEnum rabbitMqQueueEnum) {
        QueueConfigEnum queueEnum = rabbitMqQueueEnum.getQueueConfigEnum();
        rabbitAdmin.declareQueue(new Queue(rabbitMqQueueEnum.getQueueName(),
                queueEnum.isDurable(), queueEnum.isExclusive(), queueEnum.isAutoDelete(), queueEnum.getArguments()));

    }

    /**
     * 注册绑定关系
     * @param rabbitAdmin RabbitAdmin 实例，用于管理队列和交换机的声明
     * @param rabbitMqQueueEnum 自定义队列枚举，包含交换机的配置信息
     */
    public void createBindingHandle(RabbitAdmin rabbitAdmin, RabbitMqQueueEnum rabbitMqQueueEnum) {
        // 绑定
        rabbitAdmin.declareBinding(new Binding(
                // queue名称
                rabbitMqQueueEnum.getQueueName(),
                Binding.DestinationType.QUEUE,
                // exchange名称
                rabbitMqQueueEnum.getExchangeName(),
                // queue的routingKey
                rabbitMqQueueEnum.getRoutingKey(),
                null));
    }

    /**
     * 用于创建延迟队列的交换机
     */
    public static class CustomDelayedExchange extends CustomExchange {
        public CustomDelayedExchange(String name, boolean durable, boolean autoDelete, String delayedType) {
            super(name, "x-delayed-message", durable, autoDelete, Collections.singletonMap("x-delayed-type", delayedType));
        }
    }
}
